
	$$.Utf16to8 = function (str) {
		var out, i, len, c;
		out = "";
		len = str.length;
		for (i = 0; i < len; i++) {
			c = str.charCodeAt(i);
			if ((c >= 0x0001) && (c <= 0x007F)) {
				out += str.charAt(i);
			} else if (c > 0x07FF) {
				out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
				out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
				out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
			} else {
				out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
				out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
			}
		}
		return out;
    };
    
	$$.B64ToBlob = function (b64, mime) {
		if (!b64) return null;
		if (typeof b64 !== "string") return null;
		var idx = b64.indexOf(",", 0);
		if (idx >= 0) b64 = b64.substr(idx + 1);
		b64 = b64.replace(/\s/g, '');
		if (!mime) mime = "application/octet-stream";
		try {
			var binary = window.atob(b64);
			var len = binary.length;
			var buf = new ArrayBuffer(len);
			var view = new Uint8Array(buf);
			for (var i = 0; i < len; i++) {
				view[i] = binary.charCodeAt(i);
			}
			var blob = new Blob([view], { type: mime });
			return blob;
		}
		catch (e) { console.error(e); return null; }
    };
    
	$$.UrlToBlob = function (url, mime, callback) {
		if (!callback) callback = emptyfunc;
		if (!url) { callback(); return; }
		//if (url instanceof Blob) { callback(url); return; }
		if (typeof url == 'object') { callback(url); return; }
		if (typeof url !== "string") { callback(); return; }
		var xhr = new XMLHttpRequest();
		xhr.responseType = "blob";
		xhr.onerror = xhr.onabort = function () { callback(); };
		xhr.onload = function () {
			var blob = xhr.response;
			if (blob instanceof Blob) callback(blob);
			else callback();
		};
		xhr.open("GET", url, true);
		xhr.send();
    };
    
	$$.BlobToUrl = function (b64, mime, callback) {
	    if (!callback) callback = emptyfunc;
	    if (!b64) { callback(); return; }
	    var blob = null;
	    //if (b64 instanceof Blob) blob = b64;
	    if (typeof b64 == 'object') blob = b64;
	    else {
	        blob = me.B64ToBlob(b64, mime);
	        if (!blob) { callback(); return; }
	    }
		if (window.URL) {
			try {
				var url = window.URL.createObjectURL(blob);
				if (url) { callback(url); return; }
			}
			catch (ex) { }
		}

		if (window.FileReader) {
			var reader = new window.FileReader();
			reader.onerror = function () { callback(); };
			reader.onload = function () { callback(reader.result); }
			reader.readAsDataURL(blob);
		}
		else callback();
	};